package com.insurance.modules.claim.service.impl;

import cn.hutool.crypto.digest.DigestAlgorithm;
import cn.hutool.crypto.digest.Digester;
import cn.hutool.http.HttpRequest;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.insurance.common.common.ResponseData;
import com.insurance.common.enums.ResponseEnum;
import com.insurance.modules.claim.service.OssFileManagermentService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;

import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.text.SimpleDateFormat;
import java.util.Base64;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 文件上传实现类
 */
@Slf4j
@Service("OssFileManagermentService")
public class OssFileManagermentServiceImpl implements OssFileManagermentService {

    private final String tokenUri = "/authentication/getAccessToken";
    private final String uploadUri = "/generalservice/file/upload";
    private final String downloadUri = "/generalservice/file/download";
    private final String deleteUri = "/generalservice/file/delete";

    private final String REDIS_TOKEN_KEY = "uploadAccessToken";


    private @Value("${upload.url}") String url;
    private @Value("${upload.config.appId}") String appId;
    private @Value("${upload.config.appSecret}") String appSecret;

    private @Value("${upload.preview.path}") String previewPath;
    private @Value("${upload.preview.url}") String previewUrl;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    /**
     * 文件上到osss
     * @param jsonString
     * @return
     */
    @Override
    public ResponseData<String> uploadFile(JSONObject jsonString) {
        long start = System.currentTimeMillis();
        log.info("uploadFile start====="+ start);
        String accessToken = getAccessToken();
        long end = System.currentTimeMillis();
        log.info("uploadFile accessToken====="+ (end - start));
        String file = "";
        String path = "";
        try {
            file = jsonString.get("file").toString();
            path = jsonString.get("path").toString();
        }catch (Exception e) {
            return ResponseData.error("文件路径或文件内容有误");
        }
        Map<String, String> paramMap = new HashMap<>();
        paramMap.put("file", file);
        paramMap.put("fileName", path.split("\\.")[0]);
        paramMap.put("filePath", path);
        start = System.currentTimeMillis();
        log.info("uploadFile before post ====="+ (start - end));
        HttpRequest httpRequest = HttpRequest.post(url + uploadUri)
                .header("token", accessToken)
                .header("appId", appId)
                .header("Content-Type", "application/json;charset:utf8")
                .body(JSONObject.toJSONString(paramMap));
        String result = httpRequest.execute().body();
        end = System.currentTimeMillis();
        log.info("uploadFile after post ====="+ (end - start));
        log.info(path+"uploadFile>>result: "+result);
        JSONObject jsonObject = JSON.parseObject(result);
        if(!jsonObject.getString("code").equals("0")){
            return ResponseData.error(ResponseEnum.ERROR.getCode(), jsonObject.getString("msg"));
        }
        start = System.currentTimeMillis();
        log.info("uploadFile end ====="+ (start - end));
        log.info("uploadFile final ====="+ start);
        return ResponseData.success(ResponseEnum.SUCCESS.getCode(), jsonObject.getString("msg"));
    }

    /**
     * 下载OSS文件
     * @param jsonString
     * @return
     */
    public ResponseData<String> downloadFile(JSONObject jsonString){
        String path = jsonString.get("path").toString();
        String accessToken = getAccessToken();

        Map<String, String> paramMap = new HashMap<>();
        paramMap.put("fileName", path.split("\\.")[0]);
        paramMap.put("filePath", path);
        HttpRequest httpRequest = HttpRequest.post(url + downloadUri)
                .header("token", accessToken)
                .header("appId", appId)
                .header("Content-Type", "application/json;charset:utf8")
                .body(JSONObject.toJSONString(paramMap));
        String result = httpRequest.execute().body();
        log.info(path+"downloadFile>>result: "+result);
        JSONObject jsonObject = JSON.parseObject(result);
        if(!jsonObject.getString("code").equals("0")){
            return ResponseData.error(ResponseEnum.ERROR.getCode(), jsonObject.getString("msg"));
        }
        return ResponseData.success(jsonObject.getString("msg"));
    }

    /**
     * 删除OSS文件
     * @param jsonString
     * @return
     */
    public ResponseData<String> deleteFile(JSONObject jsonString){
        String path = jsonString.get("path").toString();
        String accessToken = getAccessToken();

        Map<String, String> paramMap = new HashMap<>();
        paramMap.put("fileName", path.split("\\.")[0]);
        paramMap.put("filePath", path);
        HttpRequest httpRequest = HttpRequest.post(url + deleteUri)
                .header("token", accessToken)
                .header("appId", appId)
                .header("Content-Type", "application/json;charset:utf8")
                .body(JSONObject.toJSONString(paramMap));
        String result = httpRequest.execute().body();
        log.info(path+",deleteFile>>result: "+result);
        JSONObject jsonObject = JSON.parseObject(result);
        if(!jsonObject.getString("code").equals("0")){
            return ResponseData.error(ResponseEnum.ERROR.getCode(), jsonObject.getString("msg"));
        }
        return ResponseData.success(ResponseEnum.SUCCESS.getCode(), jsonObject.getString("msg"));
    }

    @Override
    public ResponseData<String> previewFile(JSONObject jsonString) {
        String path = jsonString.get("path").toString();
        //1、先判断临时文件夹下有没有该文件
        File file = new File(previewPath + path);
        if(file.exists()){
            //直接返回改文件url
            return ResponseData.success(previewUrl + path);
        }
        //下载文件到临时文件夹，返回url
        ResponseData<String> responseData = downloadFile(jsonString);
        if(responseData.getCode() != ResponseEnum.SUCCESS.getCode()){
            //下载失败，直接返回
            return responseData;
        }
        try {
            file.createNewFile();
            String base64Str = responseData.getData().toString();
            byte[] bytes = Base64.getDecoder().decode(base64Str.split("base64,")[1]);
            try (FileOutputStream outputStream = new FileOutputStream(file);
                 ByteArrayInputStream inputStream = new ByteArrayInputStream(bytes)) {

                byte[] buffer = new byte[1024];
                int bytesRead;
                while ((bytesRead = inputStream.read(buffer)) != -1) {
                    outputStream.write(buffer, 0, bytesRead);
                }
                outputStream.flush();
            }
        } catch (Exception e) {
            log.error("预览复制图片error：", e);
            if(file.exists()){
                file.delete();
            }
            return responseData;
        }
        return ResponseData.success(previewUrl + path);
    }

    private String getAccessToken(){
        String token = "";
        try{
            token = stringRedisTemplate.opsForValue().get(REDIS_TOKEN_KEY);
        }catch (Exception e){
            log.error("getAccessToken error:{}", e);
        }
        if(StringUtils.isBlank(token)){
            token = refreshAccessToken();
        }
        return token;
    }
    private String refreshAccessToken(){
        Map<String, String> paramMap = new HashMap<>();
        String format = "yyyyMMdd24HHmmss";
        SimpleDateFormat sdf = new SimpleDateFormat(format);
        String date = sdf.format(new Date());
        paramMap.put("appId", appId);
        paramMap.put("appSecret", appId);
        paramMap.put("timeStamp", date);
        Digester md5 = new Digester(DigestAlgorithm.MD5);
        String digestHex = md5.digestHex(appId+appSecret+date);
        digestHex = md5.digestHex(digestHex);
        HttpRequest httpRequest = HttpRequest.post(url + tokenUri)
                .header("sign", digestHex)
                .header("Content-Type", "application/json;charset:utf8")
                .body(JSONObject.toJSONString(paramMap));
        String result = httpRequest.execute().body();
        JSONObject jsonObject = JSON.parseObject(result);
        String token = "";
        if(jsonObject.getString("code").equals("00000")){
            token = jsonObject.getString("data");
            try{
                stringRedisTemplate.opsForValue().set(REDIS_TOKEN_KEY, token, 2, TimeUnit.HOURS);
            }catch (Exception e){
                log.error("refreshAccessToken error:{}", e);
            }
        }
        return token;
    }
}
